grammar plp4;

@header {
	import java.lang.String;
	import java.util.ArrayList;
}
 
@rulecatch {
	catch (RecognitionException e) {
		reportError(e);
		System.exit(1);
	}
}
@members {
	private TSimbolos tSimbolos = new TSimbolos(null,null);
	private TClases tClases = new TClases();
	public int posicionSimbolo=0;
	public int maxPila = 100;
	public boolean enCatch = false;
	public String excepcion = "";
	public int fila, columna;
	public String error;

	public String ponBlancos(int num) {
	        String cad = "";
	        for (int i = 0; i < num * 4; i++) {
	            cad += " ";
       	 	}
        	return cad;
    	}
    	
    	private void ErrorSem1(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 1 ("+fila+","+columna+"): '"+ disfunka +"' ya existe en este ambito");
		System.exit(5);
	}

	private void ErrorSem2(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 2 ("+fila+","+columna+"): simbolo '"+ disfunka +"' no ha sido declarado");
		System.exit(5);
	}

	private void ErrorSem3(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 3 ("+fila+","+columna+"): tipo incompatible en operador aritmetico '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem4(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 4 ("+fila+","+columna+"): tipo incompatible en operador logico '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem5(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 5 ("+fila+","+columna+"): la expresion debe ser de tipo booleano en la instruccion '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem6(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 6 ("+fila+","+columna+"): tipos incompatibles en la instruccion de asignacion");
		System.exit(5);
	}

	private void ErrorSem7(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 7 ("+fila+","+columna+"): tipos incompatibles en la instruccion de lectura");
		System.exit(5);
	}

	private void ErrorSem8(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 8 ("+fila+","+columna+"): tamanyo incorrecto");
		System.exit(5);
	}
	private void ErrorSem9(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 9 ("+fila+","+columna+"): numero insuficiente de indices en el array '"+ disfunka +"'");
		System.exit(5);
	}


	private void ErrorSem10(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 10 ("+fila+","+columna+"): numero de dimensiones incorrecto");
		System.exit(5);
	}

	private void ErrorSem11(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 11 ("+fila+","+columna+"): el identificador '"+ disfunka +"' no es de tipo array");
		System.exit(5);
	}

	private void ErrorSem12(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 12 ("+fila+","+columna+"): demasiados indices");
		System.exit(5);
	}

	private void ErrorSem13(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 13 ("+fila+","+columna+"): indice de tipo incompatible");
		System.exit(5);
	}

	private void ErrorSem14(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 14 ("+fila+","+columna+"): tipo '" + disfunka +"' incompatible con la declaracion");
		System.exit(5);
	}

	private void ErrorSem15(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 15 ("+fila+","+columna+"): la variable que se intenta modificar es de solo lectura");
		System.exit(5);
	}

	private void ErrorSem16(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 16 ("+fila+","+columna+"): instruccion '" + disfunka +"' no permitida fuera de un bucle");
		System.exit(5);
	}

	private void ErrorSem17(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 17 ("+fila+","+columna+"): la expresion debe ser de tipo numerico");
		System.exit(5);
	}
	
	private void ErrorSem18(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 18 ("+fila+","+columna+"): sentencia '"+ lexema + "' no permitida en este ambito");
		System.exit(5);
	}
	
	private void ErrorSem19(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 19 ("+fila+","+columna+"): '"+ lexema + "' no es una excepcion");
		System.exit(5);
	}
	
	private void ErrorSem20(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 20 ("+fila+","+columna+"): La propiedad '"+ lexema + "' debe definir al menos un accesor");
		System.exit(5);
	}
	
	private void ErrorSem21(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 21 ("+fila+","+columna+"): La propiedad '"+ lexema + "' no puede consultarse");
		System.exit(5);
	}
	
	private void ErrorSem22(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 22: debe existir un unico metodo Main");
		System.exit(5);
	}
	
	private void ErrorSem23(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 23 ("+fila+","+columna+"): identificador '"+ lexema + "' usado incorrectamente");
		System.exit(5);
	}
	
	private void ErrorSem24(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 24 ("+fila+","+columna+"): el metodo '"+ lexema + "' ya esta definido");
		System.exit(5);
	}
	
	private void ErrorSem25(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 25 ("+fila+","+columna+"): el metodo '"+ lexema + "' no esta definido");
		System.exit(5);
	}
	
	private void ErrorSem26(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 26 ("+fila+","+columna+"): aqui no puede usarse return");
		System.exit(5);
	}
	
	private void ErrorSem27(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 27 ("+fila+","+columna+"): valor devuelto de tipo incompatible");
		System.exit(5);
	}
	private void ErrorSem28(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 28 ("+fila+","+columna+"): tipo incompatible en el parametro");
		System.exit(5);
	}
	private void ErrorSem29(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 29 ("+fila+","+columna+"): no se permite la declaracion de arrays de objetos");
		System.exit(5);
	}
	private void ErrorSem30(int fila, int columna, String lexema, String lexema2)
	{
		columna++;
		System.err.println("Error 30 ("+fila+","+columna+"): el objeto '"+ lexema + "' no es de clase '" + lexema2 + "'");
		System.exit(5);
	}
	private void ErrorSem31(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 31 ("+fila+","+columna+"): miembro '"+ lexema + "' no accesible desde Main");
		System.exit(5);
	}private void ErrorSem32(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 32 ("+fila+","+columna+"): la referencia es de tipo objeto");
		System.exit(5);
	}
	private void ErrorSem33(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 33 ("+fila+","+columna+"): tipo incompatible con el operador relacional '"+ lexema + "'");
		System.exit(5);
	}
	private void ErrorSem34(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 34 ("+fila+","+columna+"): constructor usado incorrectamente");
		System.exit(5);
	}
	private void ErrorSem35(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 35 ("+fila+","+columna+"): un constructor no puede devolver nada");
		System.exit(5);
	}
	private void ErrorSem36(int fila, int columna, String lexema)
	{
		columna++;
		System.err.println("Error 36 ("+fila+","+columna+"): un metodo debe devolver algo");
		System.exit(5);
	}

	public void emitErrorMessage(String mensaje)
	{
		System.err.println(mensaje);
		System.exit(1);
	}


}

@lexer::members {
	public void emitErrorMessage(String mensaje)
	{
		System.err.println(mensaje);
		System.exit(1);
	}
}


s [String entrada] returns [String eixida]
	@init{
		$eixida= "";
	}:
	{
		$eixida+= ".assembly extern mscorlib{}\n" +
			  ".assembly '" + entrada +"' {}\n";
	}
	(clase{
		$eixida += $clase.eixida;
	})+
	;


clase returns [String eixida]
	@init{
		$eixida= "";
		Simbolo zlase = null;
		
	}:
	CLASS ID{
		
	}
	LLAVEI {
		$eixida+= ".class "+ $ID.text + " extends [mscorlib]System.Object {\n" +
			".method public specialname rtspecialname instance void .ctor() cil managed\n{"+
			".maxstack 1\nldarg.0\ncall instance void [mscorlib]System.Object::.ctor()\nret\n}\n";
		zlase = tClases.nuevo($ID.text);
		tSimbolos = new TSimbolos(null,zlase);
		if (zlase == null){
			//CLASE YA DECLARADA, ERROR??
		
		}
		
	}(
	miembro[zlase]{		
	
	$eixida += $miembro.eixida + "}\n";
	})+
	LLAVED {
		tSimbolos = tSimbolos.pop();
	}
	;

metodo[Simbolo zlase] returns [String eixida, Simbolo smetodo, Simbolo.TipoRetorno tipo]
	@init{
		$eixida= "";
		String locales="";
		$tipo = Simbolo.TipoRetorno.REAL;
		//tSimbolos = null;
		
	}:
	PUBLIC STATIC VOID MAIN{
		if(tSimbolos.busca("Main")!=null){
			//ERRORACO
		}	
	
		$zlase.tabla.nuevo("Main",Simbolo.TipoRetorno.VOID,Simbolo.ClaseDato.METODO);
		
	
		$smetodo = zlase.tabla.busca("Main");
	
		$smetodo.clasePadre = zlase;
	
		tSimbolos = new TSimbolos(tSimbolos,$smetodo);
	
		
	} PARI PARD
	bloque[true,zlase]{

		$eixida+=".method static public void main () cil managed\n{\n.entrypoint\n.maxstack " +
		(maxPila) +"\n.locals(" + TSimbolos.limpiaLocals($bloque.locals) + ")\n" + $bloque.eixida +"ret\n}\n";
		tClases.mains++;	
		tSimbolos = tSimbolos.pop();
	}
	|
	visibilidad(tiposimple{
		$tipo = $tiposimple.tipo;
		//dolarlocales = dolartiposimple.locals;
	
	
	})? ID PARI args PARD{
		Simbolo saux = new Simbolo($ID.text, $tipo, Simbolo.ClaseDato.METODO,$zlase.tabla,0);
		saux.clasePadre = zlase;
		tSimbolos = new TSimbolos(tSimbolos,saux);
		saux.params = $args.params;
		saux.tabla = tSimbolos;

	} bloque[true,zlase]{
		
		if(!tSimbolos.existe(saux)){
			

			$zlase.tabla.nuevoAPelo(saux);
			
			
			$eixida+=".method static "+ $visibilidad.eixida+" " + locales +" "+ $ID.text+ " ("+ $args.eixida +") cil managed\n{\n.maxstack " +
			(maxPila) +"\n.locals(" + TSimbolos.limpiaLocals($bloque.locals) + ")\n" + $bloque.eixida +"ret\n}\n";
			
		} else {
			
		}
		
		tSimbolos = tSimbolos.pop();
	};
	tiposimple returns [Simbolo.TipoRetorno tipo, String locals]
	@init{
		$locals = "";
	}:
	INT{
		$tipo = Simbolo.TipoRetorno.ENTERO;
		fila = $INT.line;
		columna = $INT.pos;
		error = $INT.text;
		$locals = "int32";
		
	}
	| DOUBLE{
		$tipo = Simbolo.TipoRetorno.REAL;
		fila = $DOUBLE.line;
		columna = $DOUBLE.pos;
		error = $DOUBLE.text;
		$locals = "float64";
	}
	| BOOL{
		$tipo = Simbolo.TipoRetorno.BOOLEANO;
		fila = $BOOL.line;
		columna = $BOOL.pos;
		error = $BOOL.text;
		$locals = "int32";
	};

decl returns [String eixida,  String locals, ArrayList<Simbolo> simbolos]
	@init{
		$eixida= "";
		$locals = "";
		$eixida = "";
	}:
	(
	constdecl{
		$locals = $constdecl.locals;
		$eixida = $constdecl.eixida;
		
	}
	|
	vardecl{
		$locals = $vardecl.locals;
		$simbolos = $vardecl.simbolos;	
	}
	)
	;
	
constdecl returns [String eixida, String locals]
	@init {
		$eixida = "";
		String aux = "";
		int numSimbolo = 0;
	}:
	CONST 
	tiposimple{}
	c1 = constid {
		aux = $tiposimple.locals+",";
		$eixida += $c1.eixida;
		if($tiposimple.tipo==Simbolo.TipoRetorno.BOOLEANO && $c1.tipo!=Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem6($c1.asigFila,$c1.asigColumna,$c1.asigText);
		} else if ($tiposimple.tipo!=Simbolo.TipoRetorno.BOOLEANO && $c1.tipo==Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem6($c1.asigFila,$c1.asigColumna,$c1.asigText);
		} else if ($tiposimple.tipo==Simbolo.TipoRetorno.REAL && $c1.tipo==Simbolo.TipoRetorno.ENTERO){
			$eixida += "conv.r8 \n";
		} else if ($tiposimple.tipo==Simbolo.TipoRetorno.ENTERO && $c1.tipo==Simbolo.TipoRetorno.REAL){
			$eixida += "conv.i4 \n";
		}
		
		numSimbolo = tSimbolos.nuevo($c1.nombre,$tiposimple.tipo,Simbolo.ClaseDato.CONSTANTE);
		if(numSimbolo<0){
			ErrorSem1(fila,columna,error);
		}
		$eixida += "stloc " + Integer.valueOf(tSimbolos.busca($c1.nombre).num).toString() + "\n";	
		
	}
	
	(COMA
	c2 = constid {
		if($tiposimple.tipo==Simbolo.TipoRetorno.BOOLEANO && $c2.tipo!=Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem6($c2.asigFila,$c2.asigColumna,$c2.asigText);
		} else if ($tiposimple.tipo!=Simbolo.TipoRetorno.BOOLEANO && $c2.tipo==Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem6($c2.asigFila,$c2.asigColumna,$c2.asigText);
		} else if ($tiposimple.tipo==Simbolo.TipoRetorno.REAL && $c2.tipo==Simbolo.TipoRetorno.ENTERO){
			$eixida += "conv.r8 //MAGNESIO \n";
		} else if ($tiposimple.tipo==Simbolo.TipoRetorno.ENTERO && $c2.tipo==Simbolo.TipoRetorno.REAL){
			$eixida += "conv.i4 //ESTRONCIO\n";
		}
		$eixida += $c2.eixida;
		aux+= $tiposimple.locals+",";
		numSimbolo = tSimbolos.nuevo($c2.nombre,$tiposimple.tipo,Simbolo.ClaseDato.CONSTANTE);
		if(numSimbolo<0){
			ErrorSem1(fila,columna,error);
		}
		$eixida += "stloc " + Integer.valueOf(tSimbolos.busca($c2.nombre).num).toString() + "\n";	
		//$eixida += "stloc " + Integer.valueOf(numSimbolo).toString() + "\n";	
	}
	)*
	PYC{
		$locals = aux;
	}
	;
	
constid returns [String eixida, String nombre, int asigFila, int asigColumna,String  asigText, Simbolo.TipoRetorno tipo]
	@init {
		$eixida = "";
	}:
	ID{
		$nombre = $ID.text;
		fila = $ID.line;
		columna = $ID.pos;
		error = $ID.text;
		
	} ASIG{
		$asigFila = $ASIG.line;
		$asigColumna = $ASIG.pos;
		$asigText = $ASIG.text;
		
	} (
		ENTERO{
			$eixida = "ldc.i4 " + Integer.valueOf($ENTERO.text).toString() + "\n";
			$tipo = Simbolo.TipoRetorno.ENTERO;
		
		} | REAL{
		
			$eixida = "ldc.r8 " + Double.valueOf($REAL.text).toString() + "\n";
			$tipo = Simbolo.TipoRetorno.REAL;
		
		} | BOOLEANO{
			$tipo = Simbolo.TipoRetorno.BOOLEANO;
			if($BOOLEANO.text.equals("True")){
				$eixida = "ldc.i4 1\n";
			} else {
				$eixida = "ldc.i4 0\n";				
			}
		}
	)
	;
	
vardecl returns [String locals, ArrayList<Simbolo> simbolos ]
	@init {

		String aux = "";
		int auxx;
		Simbolo sauxx;
		$simbolos = new ArrayList<Simbolo>();
		
	}:
	tipo {
		aux = $tipo.locals;	
	}	
	v1 = varid {
		if(v1.esVector){
			auxx= tSimbolos.nuevo($v1.nombre,$tipo.tipo,$v1.dims);	
			aux+= "[],";
			if(auxx<0){
				ErrorSem1(fila,columna,error);
			}
		} else {
			aux+=",";
			auxx = tSimbolos.nuevo($v1.nombre,$tipo.tipo,Simbolo.ClaseDato.VARIABLE);
				
			if(auxx<0){
				ErrorSem1(fila,columna,error);
			}
		}
		sauxx = tSimbolos.busca($v1.nombre);
		sauxx.clasePropia = $tipo.claseDato;
		$simbolos.add(sauxx);
	
	}
	(COMA
	v2 = varid {
		aux += $tipo.locals;
		if(v2.esVector){
			auxx = tSimbolos.nuevo($v2.nombre,$tipo.tipo,$v2.dims);
			aux+= "[],";
			if(auxx<0){
				ErrorSem1(fila,columna,error);
			}
		} else {
			aux+=",";
			auxx = tSimbolos.nuevo($v2.nombre,$tipo.tipo,Simbolo.ClaseDato.VARIABLE);	
			if(auxx<0){
				ErrorSem1(fila,columna,error);
			}
		}
		$simbolos.add(tSimbolos.busca($v2.nombre));
	}
	)*
	PYC{
		$locals = aux;
	}
	;
	
varid returns [String nombre, boolean esVector, int dims]
	@init{
		int contElementos=0;
		$nombre = "";
		$dims = 0;
		$esVector = false;
	}:
	ID{
		$nombre = $ID.text;
	
	
		error = $ID.text;
		fila = $ID.line;
		columna = $ID.pos;
	}
	(CORI
	{
		$dims++;
		$esVector=true;
	}
	(COMA	
	{
		$dims++;
	}
	)*
	CORD)?
	;

instr[boolean abreTabla, Simbolo zlase] returns [String eixida,  String locals]
	@init{
		int etSalto1, etSalto2, etSalto3, etSalto4;
		Simbolo simbaux= null;
		$eixida="";
		int numSimbolo,numSimbolo2;
		boolean addop = false;
		Simbolo s;
		Simbolo.TipoRetorno ttp;
		$locals="";
	}:
	bloque[$abreTabla,zlase] {
		$eixida += $bloque.eixida;
		$locals += $bloque.locals;
	}
	|
	fifi= IF PARI
	expr[zlase]{
		if($expr.tipo!=Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem5($fifi.line,$fifi.pos,$fifi.text);
		}
		etSalto1 = TSimbolos.saltos++;
		etSalto2 = TSimbolos.saltos++;
		etSalto3 = TSimbolos.saltos++;
		
		$eixida += "//x IF () \n" +$expr.eixida;
		$eixida += "ldc.i4 0\n";
		$eixida += "bne.un L" + etSalto1 +"\n";
		$eixida += "br L" + etSalto2 +"\n";
		$eixida += "//IF(x)\n";
	}
	PARD
	i1= instr[true,zlase]
	{
		$eixida +="L" + etSalto1 +":\n";
		$eixida +=$i1.eixida;
		$eixida +="br L" + (etSalto3)+"\n";
		$eixida +="//IF(){x}\n";
		$eixida +="L" + (etSalto2) +":\n";
		$locals += $i1.locals;
	}
	(ELSE i2=instr[true,zlase]{
		
		$eixida += $i2.eixida;
		$locals += $i2.locals;
	}
	)?{
		$eixida += "L" + (etSalto3) +":\n";
		$eixida+="//IF(){}x\n";
	}
	|
	WHILE PARI
	{
		etSalto1 = TSimbolos.saltos++;
		etSalto2 = TSimbolos.saltos++;
		etSalto3 = TSimbolos.saltos++;
		$eixida +="L" + etSalto1 +":\n";
		TSimbolos.apila("br L" + etSalto1 +"//while A \n","br L" + etSalto3 +"//while B \n");
	}
	expr[zlase]
	{
		if($expr.tipo!=Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem5($WHILE.line,$WHILE.pos,$WHILE.text);
		}
		$eixida += $expr.eixida;
		$eixida += "ldc.i4 0\n";
		$eixida += "bne.un L" + etSalto2 +"\n";
		$eixida += "br L" + etSalto3 +"//while C \n";
	}
	PARD
	i3= instr[true,zlase]
	{
		$eixida +="L" + etSalto2 +":\n";
		$eixida += $i3.eixida;
		$eixida += "br L" + etSalto1 +"//while D \n";
		$eixida +="L" + etSalto3 +":\n";
		TSimbolos.desapila();
		$locals+= $i3.locals;
	}	
	|
	FOR PARI{
	 	tSimbolos = new TSimbolos(tSimbolos,null);	
	 	etSalto1 = TSimbolos.saltos++;
		etSalto2 = TSimbolos.saltos++;
		etSalto3 = TSimbolos.saltos++;
		etSalto4 = TSimbolos.saltos++;
		TSimbolos.apila("br L" + Integer.valueOf(etSalto4).toString() +"//FOR A \n","br L" + Integer.valueOf(etSalto3).toString() +"//FOR B \n");
		
		
	}
	 INT ID ASIG{
	 	
		numSimbolo = tSimbolos.nuevo($ID.text,Simbolo.TipoRetorno.ENTERO,Simbolo.ClaseDato.CONSTANTE);
		$locals+= "int32,";
		
	} e1 = expr[zlase]{
		/*if($e1.tipo==Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem17($ID.line,$ID.pos,$ID.text);
		}*/
		$eixida = $e1.eixida;
		if($e1.tipo == Simbolo.TipoRetorno.REAL){
			$eixida += "conv.i4\n";	
		} 
		$eixida += "stloc " + Integer.valueOf(numSimbolo).toString() + "\n"; 
	}
	TO
	e2=expr[zlase]{
		$eixida += $e2.eixida;	
		if($e2.tipo==Simbolo.TipoRetorno.REAL){
			$eixida+= "conv.i4 //RADIO\n";
		} else if($e2.tipo==Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem17($TO.line,$TO.pos,$TO.text);
		}
		numSimbolo2 = tSimbolos.nuevo($TO.text,Simbolo.TipoRetorno.ENTERO,Simbolo.ClaseDato.CONSTANTE);
		$locals+= "int32,";
		$eixida += "stloc " + numSimbolo2 + "\n";
		$eixida += "ldloc " + numSimbolo + " //16MEGAPIXEL\n";
		$eixida +="L" + etSalto1 +": //INTERDEMILAN \n";
		$eixida += "ldloc "+ numSimbolo2 +" //17MEGAPIXEL\n";
	} 
	STEP (ADDOP{
		addop = true;
	})? ENTERO PARD{
		
		if(addop && $ADDOP.text.equals("-")){
			$eixida += "bge L" + etSalto2 + "\n";
		} else {
			$eixida += "ble L" + etSalto2 + "\n";
		}

		$eixida += "br L" + etSalto3 +"//FOR c \n";
	}
	i5=instr[false,zlase]{
		$eixida +="L" + etSalto2 +":\n";
		$eixida += $i5.eixida;
		$eixida +="L" + etSalto4 +":\n";
		$eixida += "ldloc " + Integer.valueOf(numSimbolo).toString() + "\n";
		$eixida += "ldc.i4 " + $ENTERO.text + "\n //En honor a Marta \n";
		if(addop && $ADDOP.text.equals("-")){
			$eixida += "sub\n";
		} else {
			$eixida += "add\n";
		}
		$eixida += "dup\n";
		$eixida += "stloc " + Integer.valueOf(numSimbolo).toString() + "\n";
		
		
		$eixida += "br L" + etSalto1 +"//FOR D \n";
		
		
		
		$eixida +="L" + etSalto3 +":\n";
		TSimbolos.desapila();
		tSimbolos = tSimbolos.pop();
		$locals+= $i5.locals;
	}
	|
	BREAK PYC{
		if(TSimbolos.isVacia()){
			ErrorSem16($BREAK.line, $BREAK.pos, $BREAK.text);
		} else {
			$eixida+= TSimbolos.desapilaSuave()[1];	
		}
	}
	|
	CONTINUE PYC{	
		if(TSimbolos.isVacia()){
			ErrorSem16($CONTINUE.line, $CONTINUE.pos, $CONTINUE.text);	
		} else {
			$eixida+= TSimbolos.desapilaSuave()[0];	
		}
	
	}
	|
	ref[true,zlase]{
	}
	cambio[$ref.error15,zlase]	
	{	
		if(error.equals("readline")){
			if($ref.tipo!=$cambio.tipo){
				ErrorSem7($cambio.asL,$cambio.asC,error);
			}
		
		}
		if($ref.tipo==Simbolo.TipoRetorno.BOOLEANO && $cambio.tipo!=Simbolo.TipoRetorno.BOOLEANO 
			|| $ref.tipo!=Simbolo.TipoRetorno.BOOLEANO && $cambio.tipo== Simbolo.TipoRetorno.BOOLEANO){
				ErrorSem6($cambio.asL,$cambio.asC,error);
			}
		
		if(!$cambio.vector && !$ref.vector){
			$eixida += $cambio.eixida;
				if($ref.tipo == Simbolo.TipoRetorno.ENTERO && $cambio.tipo == Simbolo.TipoRetorno.REAL){
					$eixida += "conv.i4 //CROMO\n";
				} else if($ref.tipo == Simbolo.TipoRetorno.REAL && $cambio.tipo == Simbolo.TipoRetorno.ENTERO){
					 $eixida += "conv.r8 //HIDROGENO\n";
				}
			$eixida += $ref.eixida;
			$eixida += $ref.eixida2;
		} else {
			$eixida += $ref.eixida;
			$eixida += $cambio.eixida;
				if($ref.tipo == Simbolo.TipoRetorno.ENTERO && $cambio.tipo == Simbolo.TipoRetorno.REAL){
					$eixida += "conv.i4 //CROMO\n";
				} else if($ref.tipo == Simbolo.TipoRetorno.REAL && $cambio.tipo == Simbolo.TipoRetorno.ENTERO){
					$eixida += "conv.r8 //HIDROGENO\n";
				}
			$eixida += $ref.eixida2;
		}
		
		
	}
	|
	ID
	{
		s = tSimbolos.busca($ID.text);
		if(s==null){
			ErrorSem2($ID.line,$ID.pos,$ID.text);
		}
		
	}
	ASIG NEW tiposimple{
		if($tiposimple.tipo != s.retorno){
			ErrorSem14(fila,columna,error);
		}
		
	} 
	CORI dims[s]
	CORD
	{
		$eixida += "ldc.i4 "+ $dims.tamArray + "\n";
		$eixida += "newarr[mscorlib] System.";
		if(s.retorno==Simbolo.TipoRetorno.REAL){
			$eixida+="Double\n";
		} else {
			$eixida+="Int32\n";
		}
		$eixida += "stloc "+ String.valueOf(s.num)+"\n";
	}
	PYC
	|
	WRITELINE PARI
	expr[zlase] {
		$eixida+= $expr.eixida;
		$eixida+= "call void [mscorlib]System.Console::WriteLine(";
		if($expr.tipo==(Simbolo.TipoRetorno.ENTERO)) $eixida+= "int32)\n";
		else if($expr.tipo==(Simbolo.TipoRetorno.REAL)) $eixida+= "float64)\n";
		else if($expr.tipo==(Simbolo.TipoRetorno.BOOLEANO)) $eixida+="bool)\n";
	}
	PARD PYC
	|
	TRY{
		$eixida += ".try\n{";
		if(enCatch){
			ErrorSem18($TRY.line,$TRY.pos,$TRY.text);	
		}
	}
	bloque[true,zlase]{
		etSalto1 = TSimbolos.saltos++;
		$eixida += $bloque.eixida;
		$locals+= $bloque.locals;
		$eixida+= "leave L"+Integer.valueOf(etSalto1).toString()+"}\n";
	}
	bloquecatch[zlase]{
		$eixida+= $bloquecatch.eixida;
		$eixida += "leave L"+ Integer.valueOf(etSalto1).toString()+ "\n}\n";
		$eixida += "L"+Integer.valueOf(etSalto1).toString()+":\n";
	}
	|
	THROW (NEW EXCEPTION PARI expr[zlase]{
		//addop es que ha entrado
		addop = true;
		$eixida = $expr.eixida;
		if($expr.tipo==Simbolo.TipoRetorno.REAL){
			$eixida += "call string [mscorlib]System.Convert::ToString(float64)\n";
		} else {
			$eixida += "call string [mscorlib]System.Convert::ToString(int32)\n";
		}
  		$eixida += "newobj instance void [mscorlib]System.Exception::.ctor(string)\n";
  		$eixida += "throw\n";
	}
	PARD )?{
		if(!addop && enCatch){
			$eixida += "rethrow\n";
		} else if (!addop){
			ErrorSem18($THROW.line,$THROW.pos,$THROW.text);
		}
		
	}
	PYC
	|
	EXPLAIN ID {
		if(enCatch){
			s = tSimbolos.busca($ID.text);
			if(s.retorno!=Simbolo.TipoRetorno.EXCEPCION){
				ErrorSem19($ID.line,$ID.pos,$ID.text);
			}
			$eixida += "dup\n";
  			$eixida += "call instance string [mscorlib]System.Exception::get_Message()\n";
  			$eixida += "call void [mscorlib]System.Console::WriteLine(string)\n";
		} else {
		
			ErrorSem18($EXPLAIN.line,$EXPLAIN.pos,$EXPLAIN.text);	
		}
		
	}  PYC
	|
	RETURN expr[zlase] PYC	//NUEVA POR IMPLEMENTAR
	|
	ID ASIG NEW ID PARI params[null,zlase] PARD PYC
	|
	subref[false,zlase] PARI params[null,zlase] PARD PYC
	
	
	;



bloque[boolean abreTabla, Simbolo zlase] returns [String eixida, int tampila,  String locals]
	@init{
		$eixida = "";
	}:
	LLAVEI{
		if($abreTabla){
			tSimbolos = new TSimbolos(tSimbolos,null);
		}
	}
	declins[zlase] {
		$eixida += $declins.eixida;
		$locals = $declins.locals;
	}
	LLAVED {
		if(abreTabla){
			tSimbolos = tSimbolos.pop();
		}
		
	}
	;
	
bloquecatch[Simbolo zlase] returns [String eixida]
	@init{
		$eixida = "";
	}:{
		enCatch = true;
	}
	CATCH{
		$eixida += "catch [mscorlib]System.Exception\n{\n";
	
	} PARI EXCEPTION ID{
		tSimbolos.nuevo($ID.text,Simbolo.TipoRetorno.EXCEPCION,Simbolo.ClaseDato.CONSTANTE);
	} PARD bloque[true,zlase]{ 
		$eixida+=$bloque.eixida;
	}{
		enCatch = false;
	};

declins[Simbolo zlase] returns [String eixida,String locals]
	@init{
		$eixida= "";
		$locals = " ";
	}:
	(
	instr[true,zlase]{
		$eixida += $instr.eixida;
		$locals += $instr.locals;
	}
	|
	decl{
		$eixida += $decl.eixida;
		$locals += $decl.locals;
	}
	)*
	;

dims[Simbolo s] returns [int tamArray]
	@init
	{
		$tamArray=1; 
		int cont =0;
	}:
	e1=ENTERO
	{
		if(!(Integer.valueOf($e1.text)>0)){
			ErrorSem8($e1.line,$e1.pos,$e1.text);
		}
		if(cont<s.dims.size()){
			s.dims.set(cont,Integer.valueOf($e1.text));
			cont++;		
		} else {
			ErrorSem10(fila,columna,error);
		}
		tamArray*=Integer.valueOf($e1.text);
	}
	(COMA e2=ENTERO
	{
		if(!(Integer.valueOf($e2.text)>0)){
			ErrorSem8($e2.line,$e2.pos,$e2.text);
		}
		if(cont<s.dims.size()){
			s.dims.set(cont,Integer.valueOf($e2.text));
			cont++;		
		} else {
			ErrorSem10($COMA.line,$COMA.pos,$COMA.text);
		}
		tamArray*=Integer.valueOf($e2.text);
	})*
	;


cambio [boolean error15, Simbolo zlase] returns [String eixida, Simbolo.TipoRetorno tipo, int asL, int asC, boolean vector]
	@init{
		$eixida= "";
		$vector = false;
	}:
	ASIG{		
		fila = $ASIG.line;
		$asL= fila;
		columna = $ASIG.pos;
		$asC=columna;
		error = $ASIG.text;
		if($error15){
			ErrorSem15($ASIG.line,$ASIG.pos,error);
		}
	}
	expr[zlase]{
		$eixida += $expr.eixida;
		$tipo = $expr.tipo;
		$vector = $expr.vector;
	}
	PYC {
	}
	|
	PUNTO READLINE{
		$asL = $READLINE.line;
		$asC = $READLINE.pos;
		error = "readline";
		if($error15){
			ErrorSem15($READLINE.line,$READLINE.pos,error);
		}
	} PYC{
	$eixida += "call string [mscorlib]System.Console::ReadLine()\n";
	if($READLINE.text.contains("int")){
			$eixida += "call int32 [mscorlib]System.Int32::Parse(string)\n";
			$tipo = Simbolo.TipoRetorno.ENTERO;
	} else if($READLINE.text.contains("double")){
			$eixida += "call float64 [mscorlib]System.Double::Parse(string)\n";
			$tipo = Simbolo.TipoRetorno.REAL;
	} else if($READLINE.text.contains("bool")){
			$eixida += "call bool [mscorlib]System.Boolean::Parse(string)\n";
			$tipo = Simbolo.TipoRetorno.BOOLEANO;
	}

	}
	;

expr[Simbolo zlase] returns [String eixida, Simbolo.TipoRetorno tipo, boolean vector]
	@init{	
		Simbolo.TipoRetorno tipo2;
		$eixida="";
		$vector = false;
	}:
        ea1=eand[zlase]{

		$tipo = $ea1.tipo;
		$eixida += $ea1.eixida;
		$vector = $ea1.vector;
        }
        (OR
        ea2= eand[zlase] {
	
		if($ea1.tipo!=Simbolo.TipoRetorno.BOOLEANO || ea2.tipo!=Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem4($OR.line,$OR.pos,$OR.text);
		}
		$eixida += $ea2.eixida;
		$eixida += "or\n";
		$tipo = Simbolo.TipoRetorno.BOOLEANO;
        }
        )*
    ;

eand[Simbolo zlase] returns [String eixida, Simbolo.TipoRetorno tipo, boolean vector]
	@init{
		String eixida2;
		$eixida ="";
		$vector = false;
	}:
        e1=erel[zlase]{
		$tipo = $e1.tipo;
		$eixida += $e1.eixida;
		$vector = $e1.vector;
        }
        (AND
        e2= erel[zlase] {
		
		if($e1.tipo!=Simbolo.TipoRetorno.BOOLEANO || e2.tipo!=Simbolo.TipoRetorno.BOOLEANO)
		{
			ErrorSem4($AND.line,$AND.pos,$AND.text);
		}
		$eixida += $e2.eixida;
		$eixida += "and\n";
		$tipo = Simbolo.TipoRetorno.BOOLEANO;
        }
        )*
    ;
erel [Simbolo zlase] returns [String eixida, Simbolo.TipoRetorno tipo, boolean vector]
	@init{
		Simbolo.TipoRetorno tipo2;
		$eixida ="";
		int salto1, salto2, salto3;
		$vector = false;
	}:
        e1=esum[zlase]{
		$tipo = $e1.tipo;
		$eixida += $e1.eixida;
		$vector = $e1.vector;
        }
        (RELOP
        e2=esum[zlase] {
        	
     		if($e2.tipo == Simbolo.TipoRetorno.REAL && $tipo != Simbolo.TipoRetorno.REAL){
     			$eixida+="conv.r8 //LITIO \n";
     		}
		$eixida += $e2.eixida;
		if($tipo == Simbolo.TipoRetorno.REAL && $e2.tipo != Simbolo.TipoRetorno.REAL){
     			$eixida+="conv.r8 //SODIO \n";
     		}
		$tipo=Simbolo.TipoRetorno.BOOLEANO;
		if($RELOP.text.equals("==")){
			$eixida += "beq ";
		} else if($RELOP.text.equals("!=")){
			$eixida += "bne.un ";
		} else if($RELOP.text.equals("<")){
			$eixida += "blt ";
		} else if($RELOP.text.equals(">")){
			$eixida += "bgt ";
		} else if($RELOP.text.equals("<=")){
			$eixida += "ble ";
		} else {
			$eixida += "bge ";
		}
		salto1 = TSimbolos.saltos++;
		salto2 = TSimbolos.saltos++;
		salto3 = TSimbolos.saltos++;
		
		$eixida += "L"+ salto1+ "\n";
		$eixida += "br L" + salto2 + "\n";
		$eixida += "L" + salto1+ ":\n";
		$eixida += "ldc.i4 1\n";
		$eixida += "br L" +salto3+ "\n";
		$eixida += "L" + salto2+ ":\n";
		$eixida += "ldc.i4 0\n";
		$eixida += "L" + salto3 + ":\n";
        }
        )*{
        	
        }
    ;

esum [Simbolo zlase]    returns [Simbolo.TipoRetorno tipo, String eixida, boolean vector]
	@init{
		Simbolo.TipoRetorno tipo2;
		$eixida ="";
		$vector = false;
	}:
        t1=term[zlase]{
		$tipo = $t1.tipo;
		$eixida += $t1.eixida;
		$vector = $t1.vector;
		
		
        }
        (ADDOP{
        	if($tipo == Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem3($ADDOP.line,$ADDOP.pos,$ADDOP.text);
		}
        }
        t2=term[zlase] {
        	
     	
        	if($t2.tipo == Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem3($ADDOP.line,$ADDOP.pos,$ADDOP.text);
		} else if($tipo != Simbolo.TipoRetorno.REAL && $t2.tipo == Simbolo.TipoRetorno.REAL){
			$eixida += "conv.r8 //POTASIO \n";
			$tipo = Simbolo.TipoRetorno.REAL;
		}
        	$eixida += $t2.eixida;
        	if($tipo == Simbolo.TipoRetorno.REAL && $t2.tipo != Simbolo.TipoRetorno.REAL){
			$eixida += "conv.r8 //RUBIDIO \n";
			$tipo = Simbolo.TipoRetorno.REAL;
		}
		if($ADDOP.text.equals("+")){
			$eixida += "add\n";
		} else {
			$eixida += "sub\n";
		}
		if($tipo == Simbolo.TipoRetorno.REAL || $t2.tipo == Simbolo.TipoRetorno.REAL){
			$tipo = Simbolo.TipoRetorno.REAL;
		}
        }
        )*
    ;

term[Simbolo zlase]    returns [Simbolo.TipoRetorno tipo, String eixida, boolean vector]
	@init{
		Simbolo.TipoRetorno tipo2;
		$eixida="";
		$vector = false;
	}:
        m1=factor[zlase]{
			$tipo = $m1.tipo;
			$eixida += $m1.eixida;
			$vector = $m1.vector;
			
	}(MULOP {
		if($tipo == Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem3($MULOP.line,$MULOP.pos,$MULOP.text);
		}  
	
	}m2=factor[zlase] {
	          
        	if($m2.tipo == Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem3($MULOP.line,$MULOP.pos,$MULOP.text);
		} else if($tipo == Simbolo.TipoRetorno.ENTERO && $m2.tipo == Simbolo.TipoRetorno.REAL){
			$eixida += "conv.r8 //CESIO \n";
			$tipo = Simbolo.TipoRetorno.REAL;
		}
        	$eixida += $m2.eixida;
        	if($tipo == Simbolo.TipoRetorno.REAL && $m2.tipo == Simbolo.TipoRetorno.ENTERO){
			$eixida += "conv.r8 //FRANCIO\n";
			$tipo = Simbolo.TipoRetorno.REAL;
		}
        	
		if($MULOP.text.equals("*")){
			$eixida += "mul\n";
		} else {
			$eixida += "div\n";
		}
        }
        )*
    ;

factor[Simbolo zlase]   returns [Simbolo.TipoRetorno tipo, String eixida, boolean vector]
	@init{
		$eixida= "";
		int salto1,salto2;
	}:
        base[zlase]{
		$tipo = $base.tipo;
		$eixida += $base.eixida;
		$vector = $base.vector;
        }
    	| NOT f1= factor[zlase]{
    		salto1 = TSimbolos.saltos++;
    		salto2 = TSimbolos.saltos++;
    		$tipo = $f1.tipo;
    		$eixida += $f1.eixida;
    		if($tipo!=Simbolo.TipoRetorno.BOOLEANO){
    			ErrorSem4($NOT.line,$NOT.pos,$NOT.text);
    		} else {
    			$eixida += "ldc.i4.0\n";
    			$eixida += "beq L"+ Integer.valueOf(salto1).toString()+"\n";
    			$eixida += "ldc.i4.0\n";
    			$eixida += "br L"+  Integer.valueOf(salto2).toString()+"\n";
    			$eixida += "L"+ Integer.valueOf(salto1).toString()+":\n";
    			$eixida += "ldc.i4.1\n";
    			$eixida += "L" +  Integer.valueOf(salto2).toString() + ":\n";
    		}
        }
        | PARI ADDOP f2 = factor[zlase]{
        	if($f2.tipo == Simbolo.TipoRetorno.BOOLEANO){
        		ErrorSem3($ADDOP.line,$ADDOP.pos,$ADDOP.text);
        	}
        	 if($ADDOP.text.equals("-")){
        	 	$eixida += $f2.eixida;
        	 	$eixida += "neg\n";
        	 }
        	 $tipo = $f2.tipo;
        }
        PARD
    ;

base [Simbolo zlase]   returns [Simbolo.TipoRetorno tipo, String eixida, boolean vector]
	@init{
		$eixida= "";
		$vector = false;
	}:
         ENTERO {
         	$eixida += "ldc.i4 "+ $ENTERO.text +"\n";         	 
         	$tipo = Simbolo.TipoRetorno.ENTERO;
         	fila = $ENTERO.line;
         	columna = $ENTERO.pos;
         	error = $ENTERO.text;
         }
         | REAL {
        
         	$eixida += "ldc.r8 "+ $REAL.text +"\n";
         	$tipo = Simbolo.TipoRetorno.REAL;
         	fila = $REAL.line;
         	columna = $REAL.pos;
         	error = $REAL.text;
         }
         | BOOLEANO {
         
         	if($BOOLEANO.text.equals("True")){
         		$eixida += "ldc.i4.1\n";
         	} else {
         		$eixida += "ldc.i4.0\n";
         	}
         	$tipo = Simbolo.TipoRetorno.BOOLEANO;	
         	fila = $BOOLEANO.line;
         	columna = $BOOLEANO.pos;
         	error = $BOOLEANO.text;
         }

    	| PARI expr[zlase]{
    		$vector = true;
    		$eixida += $expr.eixida;
    		$tipo = $expr.tipo;
        }
        PARD
        |
        ref [false, zlase]
        {
    		$eixida += $ref.eixida;
    		$tipo = $ref.tipo;
        }
        |
        subref[true,zlase] PARI params[null,zlase] PARD
    ;


ref[boolean escritura, Simbolo zlase] returns[int numRef, Simbolo.TipoRetorno tipo, boolean isVector, int posVector, String eixida, String eixida2, boolean error15, boolean vector]
	@init{
		Simbolo s;
		$isVector = false;
		$eixida = "";
		$eixida2 = "";
		$vector = false;
		String comodin = "";
		
		
	}:
            subref[$escritura, zlase]{
           
            $eixida = $subref.eixida;
            $error15 = $subref.error15;
            $tipo = $subref.tipo;
            $numRef = $subref.numRef;
            s = $subref.suave;

            }
          (CORI indices[s, $CORI.line, $CORI.pos,$subref.line,$subref.pos, $subref.text,zlase]
           {
           	$vector = true;
           	if(s.clase!=Simbolo.ClaseDato.VECTOR){
           		ErrorSem11($subref.line,$subref.pos,$subref.text);
           	}
           	$isVector = true;
           	$eixida += $indices.eixida;
       		
           	if(s.dims.size()<$indices.cont){
			ErrorSem9(fila,columna,error);
		}
           }
           CORD)?
           {
           	if($isVector){
           		$eixida = "ldloc "+ Integer.valueOf(s.num).toString()+ "\n";
           		$eixida += $indices.eixida;
           		if(escritura){
           			if(s.retorno == Simbolo.TipoRetorno.REAL){
           				$eixida2 += "stelem.r8\n";
           			} else {
           				$eixida2 += "stelem.i4\n";
           			}
           		} else {
           			if(s.retorno == Simbolo.TipoRetorno.REAL){
           				$eixida += "ldelem.r8\n";
           			} else {
           				$eixida += "ldelem.i4\n";
           			}
           		}
           	
           	}
           		
           }
           ;
indices[Simbolo sim, int lineCorchete, int posCorchete, int linId, int posId, String idId, Simbolo zlase] returns[String eixida,int cont]
	@init{
		$eixida="";
		int cont = 0;
		Simbolo.TipoRetorno tipo;
		int numIndices = sim.dims.size();
	
	}:
	e1 = expr[zlase]{
		tipo = $e1.tipo;
		$eixida += $e1.eixida;
		cont++;
		
		if($e1.tipo == Simbolo.TipoRetorno.BOOLEANO){
			ErrorSem13(lineCorchete,posCorchete,error);
		
		}
		if(tipo == Simbolo.TipoRetorno.REAL){
        		$eixida += "conv.i4\n";
        	}
        	
		
		/*if(cont>sim.dims.size()){
			
			ErrorSem11(linId,posId,idId);
		}*/
        }
        (COMA{
        	if(cont==1){
       			$eixida += "ldc.i4 " + Integer.valueOf(sim.calculoDims(cont)).toString()+"\n";
        		$eixida += "mul\n";
        	}
        }
        e2 = expr[zlase]{
        	cont++;
        	if(cont>sim.dims.size()){
      
			ErrorSem12($COMA.line,$COMA.pos,error);
		}
        	if($e2.tipo == Simbolo.TipoRetorno.BOOLEANO){
        		ErrorSem13($COMA.line,$COMA.pos,error);
        	
        	}
        	
        	
        	$eixida += $e2.eixida;
        	if($e2.tipo == Simbolo.TipoRetorno.REAL){
        		$eixida += "conv.i4\n";
        		
        	}
        	$eixida += "ldc.i4 " + Integer.valueOf(sim.calculoDims(cont)).toString()+"\n";
        	$eixida += "mul\n";
        	$eixida += "add\n";
        	
				
		if(cont>sim.dims.size()){
		
			ErrorSem12($COMA.line,$COMA.pos,error);
		}
        }
        )*{	
		if(sim.dims.size()>cont){
			ErrorSem9($linId,$posId,$idId);
		}
	}
	;
	
miembro[Simbolo zlase] returns [String eixida, ArrayList<Simbolo> simbolos]
	@init{
		$simbolos = new ArrayList<Simbolo>();	
		$eixida ="";	
	}:
	campo[zlase]{
		$simbolos = $campo.simbolos;
		$eixida = $campo.eixida;
				
	}	
	|
	metodo[zlase]{
		$simbolos.add($metodo.smetodo	);
		$eixida = $metodo.eixida;
		
	}
	|
	propiedad[zlase]{
		
	}
	;

	
campo[Simbolo zlase] returns [String eixida, ArrayList<Simbolo> simbolos]
	@init{
		$eixida="";
	}:
	visibilidad decl{
		$simbolos = $decl.simbolos;
		for(Simbolo s: $simbolos){
			//s.simboloPadre = clase;
			if(zlase.tabla.existe(s)){
				//ERROR EXISTE CAMPO
			} else {

				s.clasePadre = zlase;
				zlase.tabla.nuevoAPelo(s);
			}
			$eixida += ".field " + $visibilidad.eixida;
			
			if(s.retorno == Simbolo.TipoRetorno.REAL){
				$eixida += "float64 ";
			} else {
				$eixida += "int32 ";
			}
			$eixida += "'"+ s.nombre +"'\n";	
		}
	}
	;
	
visibilidad returns [String eixida, boolean privado]
	@init{
	}:
	PRIVATE{
		$privado = true;
		$eixida = "private ";
	}
	|
	PUBLIC{
		$privado = false;
		$eixida = "public ";
	
	}
	;

args returns [String eixida, ArrayList<String> params]
	@init{
		 $eixida = "";
		$params = new ArrayList<String>();
	}:
	(d1= DOUBLE{
		$eixida += "double64";
	}id1=ID{
		$params.add($id1.text);
	}(COMA d2= DOUBLE{
		$eixida += " double64";
	}id2= ID{
		$params.add($id2.text);
	
	})*)?
	;
	
propiedad[Simbolo zlase] returns [String eixida]
	@init{
	}:
	PROPERTY tiposimple ID LLAVEI accesores[zlase] LLAVED
	;
	
accesores[Simbolo zlase] returns [String exida]
	@init{
	}:
	(GET bloque[true,zlase])?
	(SET bloque[true,zlase])?
	|
	GET PYC SET PYC
	;
	
tipo returns [String exida, String locals, Simbolo.TipoRetorno tipo, Simbolo claseDato]
	@init{
		$locals = "";
	}:
	ID{
		$claseDato = tClases.busca($ID.text);
	}
	|
	tiposimple{
		$locals = $tiposimple.locals;
		$tipo = $tiposimple.tipo;	
	
	}
	;
	
params[Simbolo metodoEnCuestion, Simbolo zlase] returns[String eixida]
	@init{}:
	(expr[zlase] (COMA expr[zlase])*)?
	;
	
 subref[boolean escritura, Simbolo zlase] returns [Simbolo suave, String eixida, int line, int pos, String text, Simbolo.TipoRetorno tipo, boolean error15, int numRef]
	@init{}:{
		$line = -1;
		$pos = -1;
		$text = "";
		$eixida = "";
		String comodin= "";
		Simbolo s = null;
		TSimbolos Taux= tSimbolos;
	}
	id1= ID{
		$line = $id1.line;
		$pos = $id1.pos;
		$text = $id1.text;
		
		 
           	s = tSimbolos.busca($text);
      
           	if(s == null){
           		s = zlase.tabla.busca($text);
           		if(s == null) {
           		
           			ErrorSem2($line,$pos,$text);	
			}
           	}
           	
           	$suave = s;
           	$numRef = s.num ; 
           	$tipo = s.retorno;
           	
           	
           	if(s.num == -2){
           		 comodin += "ldarg 0\n";
           		 if(!escritura){
           			 comodin += "ldfld ";
           		} else {
           			comodin += "stfld "; 
           		}
           		 if(s.retorno == Simbolo.TipoRetorno.REAL){
           		 	comodin += "float64";
           		 } else {
           		 	comodin += "int32";
           		 }
           		 if(s.clase == Simbolo.ClaseDato.VECTOR){
           		 	comodin += "[]";
           		 }
           		 comodin += "'" + s.clasePadre + "'::'" + s.nombre + "'\n";
           		 $eixida += comodin;
           	} else {          	
           		
			if(escritura){

				if(s.clase == Simbolo.ClaseDato.CONSTANTE){
					$error15 = true;
				}
				$eixida += "stloc " + Integer.valueOf(s.num).toString()+"\n";
			} else {
		
				$eixida += "ldloc " + Integer.valueOf(s.num).toString() +"\n";
			}
	          }
	
	} ( PUNTO id2=ID{

		tSimbolos =  s.clasePropia.tabla;
		
		$line = $id2.line;
            	$pos = $id2.pos;
            	$text = $id2.text;
           	s = tSimbolos.busca($text);
           	if(s == null){
           		
           		ErrorSem2($line,$pos,$text);	
           	}
           	$suave = s;
           	$numRef = s.num ; 
           	$tipo = s.retorno;
           	           	
           	/* SALCHICHITAS */
           	if(s.num == -2){
           		 comodin += "ldarg 0\n";
           		 if(!escritura){
           			 comodin += "ldfld ";
           		} else {
           			comodin += "stfld "; 
           		}
           		 if(s.retorno == Simbolo.TipoRetorno.REAL){
           		 	comodin += "float64";
           		 } else {
           		 	comodin += "int32";
           		 }
           		 if(s.clase == Simbolo.ClaseDato.VECTOR){
           		 	comodin += "[]";
           		 }
           		 comodin += "'" + s.clasePadre + "'::'" + s.nombre + "'\n";
           		$eixida += comodin;
           	} 

	})*{
		tSimbolos = Taux;
	}
	;
	

	



NEWline          : ('\r'? '\n'|' '|'\t')+  { skip(); };
COMENTARIO       : '/*' .* '*/' {skip();};
COMENTARIOSIMPLE
	:'//' ~('\n'|'\r')* '\r'? '\n' {skip();};
PYC     :';' ;
ASIG    :'=' ;

MAIN 	:'Main';


CLASS   :'class' ;

DOUBLE  :'double';
INT     :'int' ;
BOOL	:'bool';
VOID    :'void';
PUBLIC	:'public';
STATIC	:'static';
CONST	:'const';
RETURN	:'return';
PRIVATE	:'private';
GET	:'get';
SET	:'set';
PROPERTY	: 'property';

TRY	: 'try';
CATCH	: 'catch';
EXCEPTION 
	: 'Exception';
THROW	: 'throw';
EXPLAIN : 'explain';


IF	:'if';
ELSE	:'else';
FOREACH	:'foreach';
VAR	:'var';
IN	:'in';

FOR	:'for';
TO	:'to';
STEP	:'step';
WHILE	:'while';
BREAK	:'break';
CONTINUE:'continue';
NEW	:'new';
WRITELINE
	:'System.Console.WriteLine';
READLINE:('int'|'double'|'bool')'.Parse(System.Console.ReadLine())';
PARI    :'(' ;
PARD    :')' ;
LLAVEI  :'{' ;
LLAVED  :'}' ;
CORI	:'[';
CORD	:']';
COMA	:',';
OR	:'|';
AND	:'&';
RELOP	:'=='|'!='|'<'|'>'|'<='|'>=';
ADDOP	:'+'|'-';
MULOP	:'*'|'/';
NOT	:'!';
PUNTO	:'.';
ENTERO  :('0'..'9')+ ;
REAL	:('0'..'9')+'.'('0'..'9')+ ;
BOOLEANO:'True'|'False';
ID      :('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'0'..'9')*;
